﻿using System;
using System.Windows;
using System.Collections.Generic;

namespace TouchScreenPanel
{
    class TouchScreenDetector
    {
        private Point m_down;
        private List<Point> m_move = new List<Point>();
        private Point m_up;

        /// <summary>
        /// Point where the mouse goes down / Point
        /// </summary>
        public Point MouseDownPoint
        {
            get
            {
                return m_down;
            }
            set
            {
                m_down = value;
            }
        }
        /// <summary>
        /// Point where the mouse stops / Point[]
        /// </summary>
        public Point MouseUpPoint
        {
            get
            {
                return m_up;
            }
            set
            {
                m_up = value;
            }
        }
        /// <summary>
        /// Point array when the mous moves / Point[]
        /// </summary>
        public List<Point> MouseMovePoint
        {
            get
            {
                return m_move;
            }
            set
            {
                m_move = value;
            }
        }

        public enum TouchEvent{DrawLeft = 0, DrawRight, DrawUp, DrawDown, Click, Circle, Nothing};

        /// <summary>
        /// Returns the event which has been calculated
        /// </summary>
        /// <returns>TouchEvent</returns>
        public TouchEvent GetTouchEvent()
        {
            double dx = (m_down.X - m_up.X);
            double dy = (m_down.Y - m_up.Y);
            Int32 offset = 10;
            TouchEvent tev;

            if (m_down == m_up)
            {
                //Click
                tev = TouchEvent.Click;
            }
            else if (CheckCircle() == true)
            {
                //Circle
                tev = TouchEvent.Circle;
            }
            else
            {
                if ((Math.Abs(dx)) > Math.Abs(dy))
                {
                    #region Vertikal
                    //Vertikale Verschiebung
                    if (dx < (offset * (-1)))
                    {
                        tev = TouchEvent.DrawRight;
                    }
                    else if (dx > offset)
                    {
                        tev = TouchEvent.DrawLeft;
                    }
                    else
                    {
                        if (CheckCircle() == true)
                        {
                            //Circle
                            tev = TouchEvent.Circle;
                        }
                        else if ((Math.Abs(dx)) == Math.Abs(dy))
                        {
                            //Click
                            tev = TouchEvent.Click;
                        }
                        else
                        {
                            tev = TouchEvent.Nothing;
                        }
                    }
                    #endregion
                }
                else if ((Math.Abs(dx)) < Math.Abs(dy))
                {
                    #region Horizontal
                    //Horizontale Verschiebung
                    if (dy < (offset * (-1)))
                    {
                        tev = TouchEvent.DrawDown;
                    }
                    else if (dy > offset)
                    {
                        tev = TouchEvent.DrawUp;
                    }
                    else
                    {
                        if (CheckCircle() == true)
                        {
                            //Circle
                            tev = TouchEvent.Circle;
                        }
                        else if ((Math.Abs(dx)) == Math.Abs(dy))
                        {
                            //Click
                            tev = TouchEvent.Click;
                        }
                        else
                        {
                            tev = TouchEvent.Nothing;
                        }
                    }
                    #endregion
                }
                else
                {
                    tev = TouchEvent.Nothing;
                }
            }


            return tev;
        }
        /// <summary>
        /// Returns the Speed of the mouse
        /// </summary>
        /// <returns>Int32</returns>
        public double GetTouchSpeed()
        {
            double dx = Math.Abs(m_down.X - m_up.X) * 10;
            double dy = Math.Abs(m_down.Y - m_up.Y) * 10;

            switch (GetTouchEvent())
            {
                case TouchEvent.DrawDown:
                    return (dy / m_move.Count);

                case TouchEvent.DrawUp:
                    return (dy / m_move.Count);

                case TouchEvent.DrawLeft:
                    return (dx / m_move.Count);

                case TouchEvent.DrawRight:
                    return (dx / m_move.Count);

                case TouchEvent.Circle:
                    return (0);
 
                default:
                    return (0);
            }
        }

        /// <summary>
        /// Checks if the event is a Circle
        /// </summary>
        /// <returns>Boolean</returns>
        private Boolean CheckCircle()
        {
            Int32 checksum = 0;
            Point mpoint = GetMiddlePoint();
            Decimal percent;

            foreach (Point pnt in m_move)
            {
                if (CheckMirroir(pnt, mpoint) == true)
                {
                    checksum++;
                }
            }

            percent = ((checksum * 100) / m_move.Count);

            //Offset % von Maximum
            if (percent > 15)
            {
                Int32 diff = Convert.ToInt32(GetDifference(m_down, m_up) - GetMaxDifference());
                //Offset der Differenz Länge
                if (diff < 50)
                {
                    return true;
                }
            }

            return false; 
        }
        /// <summary>
        /// Returns the middle point of a circle
        /// </summary>
        /// <returns>Point</returns>
        private Point GetMiddlePoint()
        {
            double mX = 0;
            double mY = 0;

            Point temp = m_move[m_move.Count - 1];

            foreach (Point pnt in m_move)
            {
                double diff = GetDifference(pnt, temp);

                mX += pnt.X * diff;
                mY   += pnt.Y * diff;

                temp = pnt;
            }

            double maxdiff = GetMaxDifference();

            mX = (mX / m_move.Count) / maxdiff;
            mY = (mY / m_move.Count) / maxdiff;

            return new Point((Int32)mX, (Int32)mY);
        }
        /// <summary>
        /// Returns the difference between two points
        /// </summary>
        /// <returns>double</returns>
        private double GetDifference(Point p1, Point p2)
        {
            return Math.Sqrt(Math.Pow((p1.X - p2.X), 2) + Math.Pow((p1.Y - p2.Y), 2));
        }
        /// <summary>
        /// Returns the maximal length of the pointline
        /// </summary>
        /// <returns>double</returns>
        private double GetMaxDifference()
        {
            double len = 0;
            Point temp = m_move[m_move.Count - 1];

            foreach (Point pnt in m_move)
            {
                len += GetDifference(pnt, temp);
                temp = pnt;
            }

            return len / m_move.Count;
        }
        /// <summary>
        /// Returns if a point has a mirroir point with a offset
        /// </summary>
        /// <returns>Boolean</returns>
        private Boolean CheckMirroir(Point Dpnt, Point Mpnt)
        {
            double dx = (Mpnt.X - Dpnt.X);
            double dy = (Mpnt.Y - Dpnt.Y);
            Point mirroirpnt = new Point(Mpnt.X + dx, Mpnt.Y + dy);

            //Offset des Mirroir Point
            return CheckOffset(mirroirpnt, 5);
        }
        /// <summary>
        /// Checks if a linepoint is in the offset
        /// </summary>
        /// <returns>Boolean</returns>
        private Boolean CheckOffset(Point cpnt , Int32 offset)
        {
            foreach (Point pnt in m_move)
            {
                if ((pnt.X >= (cpnt.X - offset)) && (pnt.X <= (cpnt.X + offset)) && (pnt.Y >= (cpnt.Y - offset)) && (pnt.Y <= (cpnt.Y + offset)))
                {
                    return true;
                }
            }
            return false;
        }

    }
}
